package stud.mpgame.server;

import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.mina.core.session.IoSession;

import stud.mpgame.network.IMessageReceivedListener;
import stud.mpgame.network.Message;
import stud.mpgame.network.NetworkMonitor;
import stud.mpgame.network.TCPNetworkMonitor;

import stud.mpgame.network.util.MessageFilter;
import stud.mpgame.server.game.GameProtocolHandler;

import stud.mpgame.server.game.LoginCommand;
import stud.mpgame.server.game.LoginMessageDescription;
import stud.mpgame.server.test.TestCommand;
import stud.mpgame.server.test.TestCommandDescription;
import stud.mpgame.server.test.TestSnapshot;
import stud.mpgame.server.test.TestSnapshotDescription;

import stud.mpgame.snapshot.SnapshotManager;

public class Main {

    private static final int SNAPSHOT_MANAGER_TICK_TIME = 25;
    private static final int SNAPSHOT_MANAGER_SNAPSHOT_LENGTH = 20;
    private static final int SNAPSHOT_MANAGER_INITIAL_POSITION = 10;
    private static final String defaultConfig = "server.properties";

    private final int protocolVersion = 1;

    private long startAppTime;
    private int delay;

    private NetworkMonitor networkMonitor;
    private SnapshotManager snapshotManager;
    private GameProtocolHandler gameProtocolHandler;

    private Main() throws Exception {
        startAppTime = System.currentTimeMillis();
        networkMonitor = new TCPNetworkMonitor(startAppTime, protocolVersion);
        snapshotManager = new SnapshotManager(SNAPSHOT_MANAGER_TICK_TIME, SNAPSHOT_MANAGER_SNAPSHOT_LENGTH);
    }

    private void initializationServer(String path) throws Exception {
        ServerConfiguration.getInstance().initialization(path);
        this.delay = ServerConfiguration.getInstance().getDelay();
    }

    public static void main(String[] args) throws Exception {
        Main main = new Main();
        main.initializationServer(args.length > 0 ? args[0] : defaultConfig);
        main.bind();
        main.start();
    }

    private void bind() throws Exception {
    	gameProtocolHandler = new GameProtocolHandler(networkMonitor, snapshotManager);
    	
        snapshotManager.setInitialSnapshot(new TestSnapshot(networkMonitor.nowTime(), 1000), SNAPSHOT_MANAGER_INITIAL_POSITION);

        MessageFilter messageFilter = new MessageFilter(LoginMessageDescription.getInstance());

        networkMonitor.getMessageDispatcher().addMessageReceivedListener(messageFilter,
                new IMessageReceivedListener() {
                    public void messageReceived(Message message) {
                        LoginCommand loginCommand = (LoginCommand) message.getUserObject(LoginCommand.class);
                        loginCommand.setSession(message.getFirstSession());
                        loginCommand.setTime(message.getReceivedTime());
                        snapshotManager.addCommand(loginCommand);
                    }
                });

        messageFilter = new MessageFilter(TestCommandDescription.getInstance());

        networkMonitor.getMessageDispatcher().addMessageReceivedListener(messageFilter,
                new IMessageReceivedListener() {
                    public void messageReceived(Message message) {
                        TestCommand testCommand = (TestCommand) message.getUserObject(TestCommand.class);
                        testCommand.setTime(message.getReceivedTime());
                        snapshotManager.addCommand(testCommand);
                    }
                });

        networkMonitor.bind();
    }

    private void start() throws Exception {

        int time;
        int nextUpdateTime = networkMonitor.nowTime();

        //dummy cycle
        while(true) {
            time = networkMonitor.nowTime();
            if (time >= nextUpdateTime) {
                int dt = time - nextUpdateTime + delay;
                snapshotManager.update(dt);
                nextUpdateTime += delay;
                sendTestSnapshot();
            } else {
                try {
                    Thread.sleep(nextUpdateTime - time);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    
    private void sendTestSnapshot() {
        for(IoSession session : gameProtocolHandler.getSessions()) {
            Message message = new Message(session, TestSnapshotDescription.getInstance());
            TestSnapshot snapshot = (TestSnapshot) snapshotManager.getSnapshot(networkMonitor.nowTime());
            message.putUserObject(snapshot);
            message.send();
        }
    }

}